﻿namespace Microsoft.Samples.Kinect.SkeletonBasics
{
    using System.IO;
    using System.Windows;
    using System.Windows.Media;
    using Microsoft.Kinect;
    using System;
    using System.Windows.Forms;
    using System.Collections.Generic;


    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private int fscreen = 0;
        private bool kallePaalla = false;
        private double kalleMove = 0;
        private bool laskee = false;
        private int jjj = 0;
        private bool beanthere = false;
        private bool poistumassa = false;

        private int theThird = 0;

        private int skeletoncount = 0;
        private bool shuttingdown = false;

        private DateTime endTime;

        Skeleton[] skeletons;

        ThirdPage thirdpage = new ThirdPage();

        private RoboKalle robotti;

        private string[] initValues;
        // Näitä tarvis ja tarkistakaas reffit
        // using System.IO;
        // using System.Windows.Forms;
        //
        
        public string[] readInit()
        {
            List<string> values = new List<string>();
            string appPath = System.IO.Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
            string[] lines = System.IO.File.ReadAllLines(System.IO.Path.Combine(appPath, "robokinect.ini"));
            foreach (string line in lines)
            {
                // splitataan teksti arvosta
                string[] initData = line.Split('=');
                // luetaan splitatun taulukon arvo-rivit
                for (int i = 1; i < initData.Length; i += 2)
                    values.Add(initData[i]);

            }
            // Muodostetaan initValues taulu listasta
            return values.ToArray();

        }
        

        //public int ElevationAngle { get; set; }


        private int screenshot = 0;
        /// <summary>
        /// Width of output drawing
        /// </summary>
        private const float RenderWidth = 640.0f;
        
        /// <summary>
        /// Height of our output drawing
        /// </summary>
        private const float RenderHeight = 480.0f;

        /// <summary>
        /// Thickness of drawn joint lines
        /// </summary>
        private const double JointThickness = 3;

        /// <summary>
        /// Thickness of body center ellipse
        /// </summary>
        private const double BodyCenterThickness = 10;

        /// <summary>
        /// Thickness of clip edge rectangles
        /// </summary>
        private const double ClipBoundsThickness = 10;

        /// <summary>
        /// Brush used to draw skeleton center point
        /// </summary>
        private readonly Brush centerPointBrush = Brushes.Blue;

        /// <summary>
        /// Brush used for drawing joints that are currently tracked
        /// </summary>
        private readonly Brush trackedJointBrush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 68, 192, 68));

        /// <summary>
        /// Brush used for drawing joints that are currently inferred
        /// </summary>        
        private readonly Brush inferredJointBrush = Brushes.Yellow;

        /// <summary>
        /// Pen used for drawing bones that are currently tracked
        /// </summary>
        private readonly Pen trackedBonePen = new Pen(Brushes.Green, 6);

        /// <summary>
        /// Pen used for drawing bones that are currently inferred
        /// </summary>        
        private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1);

        /// <summary>
        /// Active Kinect sensor
        /// </summary>
        private KinectSensor sensor;


        public static int showThird = 0;
        public static void changeThird(int nroo)
        {
            showThird = nroo;
        }

        public static string snapShotURL;
        public static void changeSnapShot(string snap)
        {
            snapShotURL = snap;
        }

        public static void restartProgram()
        {
            System.Windows.Forms.Application.Restart();
            System.Windows.Application.Current.Shutdown();
        }

        public static string photoName = "";
        public static void changePhotoName(string name)
        {
            photoName = name;
        }

        public static bool theEnding = false;

        public static void kalleEnding()
        {
            theEnding = true;
        }
       // public static bool theKalleReunaan = false;



        /// <summary>
        /// Drawing group for skeleton rendering output
        /// </summary>
        private DrawingGroup drawingGroup;

        /// <summary>
        /// Drawing image that we will display
        /// </summary>
        private DrawingImage imageSource;

        /// <summary>
        /// Initializes a new instance of the MainWindow class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        ~MainWindow() 
        {
            if (null != this.sensor)
            {
                this.sensor.Stop();
            }
        }

        
        
        /// <summary>
        /// Execute startup tasks
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            initValues = readInit();
            // Create the drawing group we'll use for drawing
            this.drawingGroup = new DrawingGroup();
            //robotti = new RoboKalle();

            foreach (var potentialSensor in KinectSensor.KinectSensors)
            {
                if (potentialSensor.Status == KinectStatus.Connected)
                {
                    this.sensor = potentialSensor;
                    break;
                }
            }

            if (null != this.sensor)
            {
                // Turn on the skeleton stream to receive skeleton frames
                
                this.sensor.SkeletonStream.Enable(new TransformSmoothParameters()
                {
                    Correction = 0.5f,
                    JitterRadius = 0.05f,
                    MaxDeviationRadius = 0.05f,
                    Smoothing = 0.9f
                }
                );
           
                // Add an event handler to be called whenever there is new color frame data
                this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady;

                // Start the sensor!
                try
                {
                    this.sensor.Start();
                    
                    this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;


                    if (initValues[0].Length != 0)
                    {
                        this.sensor.ElevationAngle = Convert.ToInt16(initValues[0]);
                    }
                    else
                    {
                        this.sensor.ElevationAngle = -5;
                    }
                    
                }
                catch (IOException)
                {
                    this.sensor = null;
                    toks.Text = "Kinect sensor couldnt found";

                    
                }
            }

        }

        /// <summary>
        /// Execute shutdown tasks
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (theEnding == true)
            {
                robotti.kallereunaan = true;
            }

            if(jjj != 0)
                robotti.kuolekallekuole();

            if (null != this.sensor)
            {
                this.sensor.Stop();
            }
        }

        private void keikutaKallea(int okasid, int vkasid, double kpos)
        {  
                robotti.okasi(okasid);
                robotti.vkasi(vkasid);
                robotti.jalat(kpos);          
        }
   
        /// <summary>
        /// Event handler for Kinect sensor's SkeletonFrameReady event
        /// </summary>
        /// <param name="sender">object sending the event</param>
        /// <param name="e">event arguments</param>
        /// 
        private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            
            if (showThird == 1 && theThird == 0)
            {
                theThird = 1;
                this.Content = thirdpage;
            }
            skeletons = new Skeleton[0];

            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame != null)
                {

                    skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
                    skeletonFrame.CopySkeletonDataTo(skeletons);
                }
              
            }
            
            using (DrawingContext dc = this.drawingGroup.Open())
            {
                if (theEnding == true)
                {

                    if (null != this.sensor)
                    {
                        this.sensor.Stop();
                    }
                    robotti.kallereunaan = true;

                }

                if (skeletons.Length != 0)
                {
                    skeletoncount = 0;
                    float closestDistance = 10000f; // Start with a far enough distance
                    int closestID = -1;
                    int myskel = 0;

                    foreach (Skeleton skel in skeletons)
                    {
                        if (skel.TrackingState == SkeletonTrackingState.Tracked)
                        {
                            if (skel.Position.Z < closestDistance)
                            {
                                closestID = myskel;
                                closestDistance = skel.Position.Z;
                            }
                        }

                        if (skel.TrackingState == SkeletonTrackingState.NotTracked && fscreen == 1)
                        {
                            skeletoncount++;
                        }

                        if (skeletoncount == 6 && fscreen == 1 && shuttingdown == false && theThird == 0)
                        {
                            shuttingdown = true;
                            Countdown(5, TimeSpan.FromSeconds(1), 1);
                        }

                        myskel++;

                    }

                    if (closestID != -1)
                    {
                        RenderClippedEdges(skeletons[closestID]);
                        if (fscreen == 0)
                        {
                            firstScreen.Visibility = Visibility.Hidden;
                            secondScreen.Visibility = Visibility.Visible;
                            fscreen = 1;
                        }

                        if (screenshot == 0 || theThird == 1) this.CheckPosition(skeletons[closestID]);
                    }

                }
               

            }
        }

        
        public void Countdown(int count, TimeSpan interval, int luku)
        {
            var dt = new System.Windows.Threading.DispatcherTimer();
            dt.Interval = interval;
            
            dt.Tick += (_, a) =>
            {
                varoitus.Text = "Olet liian kaukana!";

                if(robotti != null)
                    robotti.kallereunaan = true;

                if (skeletoncount < 6 && theThird == 0)
                {
                    dt.Stop();
                    shuttingdown = false;
                    varoitus.Text = "";
                }
                else {
                    if (count-- == 0)
                    {
                        dt.Stop();
         
                        if (luku == 0)
                        {
                            Countdown(5, TimeSpan.FromSeconds(1), 1);
                        }
                        if (luku == 1)
                        {
                            if (null != this.sensor)
                            {
                                this.sensor.Stop();
                            }
                            MainWindow.restartProgram();
                        }
                    }
                }

            };
            dt.Start();
        }  

        double handLenght = -1;
        bool ralhaalla;
        bool lalhaalla;

        public float AngleBetweenTwoVectors(Microsoft.Xna.Framework.Vector3 b1, Microsoft.Xna.Framework.Vector3 b2)
        {

            //AngleBetweenTwoVectors(Microsoft.Xna.Framework.Vector3.Normalize(b1), Microsoft.Xna.Framework.Vector3.Normalize(b2)).ToString();
            float dotProduct = 0.0f;
            dotProduct = Microsoft.Xna.Framework.Vector3.Dot(b1, b2);


            //return (float)Math.Acos(dotProduct);
            return (float)dotProduct;

        }
        
        private void CheckPosition(Skeleton skeleton)
        {

            double shoulderLeftX = skeleton.Joints[JointType.ShoulderLeft].Position.X;
            double shoulderLeftY = skeleton.Joints[JointType.ShoulderLeft].Position.Y;

            double shoulderRightX = skeleton.Joints[JointType.ShoulderRight].Position.X;
            double shoulderRightY = skeleton.Joints[JointType.ShoulderRight].Position.Y;

            double handRightX = skeleton.Joints[JointType.HandRight].Position.X;
            double handRightY = skeleton.Joints[JointType.HandRight].Position.Y;

            double leveysRight = Math.Abs(skeleton.Joints[JointType.WristRight].Position.X - skeleton.Joints[JointType.ShoulderRight].Position.X);
            double leveysLeft = Math.Abs(skeleton.Joints[JointType.WristLeft].Position.X - skeleton.Joints[JointType.ShoulderLeft].Position.X);

            double korkeusRight = Math.Abs(skeleton.Joints[JointType.WristRight].Position.Y - skeleton.Joints[JointType.ShoulderRight].Position.Y);
            double korkeusLeft = Math.Abs(skeleton.Joints[JointType.WristLeft].Position.Y - skeleton.Joints[JointType.ShoulderLeft].Position.Y);

            double handLeftX = skeleton.Joints[JointType.HandLeft].Position.X;
            double handLeftY = skeleton.Joints[JointType.HandLeft].Position.Y;

            if (jjj == 0 && skeleton.Joints[JointType.Head].Position.Y + 0.1 < handLeftY && skeleton.Joints[JointType.Head].Position.Y < handRightY)
            {
                robotti = new RoboKalle();

                if(initValues.Length != 0)
                    robotti.kallerange = Convert.ToInt32(initValues[1]);

                handLenght = handLeftY - shoulderLeftY;
                handLenght = handLenght * (double)0.75;
                jjj = 1;
                kalleMove = skeleton.Joints[JointType.HipCenter].Position.X;

                kallePaalla = true;

                secondScreen.Visibility = Visibility.Hidden;
                thirdScreen.Visibility = Visibility.Visible;
            }

            // Niskan ja handin korkeusero
            double differenceLeft = Math.Abs(skeleton.Joints[JointType.ShoulderLeft].Position.Y - skeleton.Joints[JointType.HandLeft].Position.Y);
            double differenceRight = Math.Abs(skeleton.Joints[JointType.ShoulderRight].Position.Y - skeleton.Joints[JointType.HandRight].Position.Y);

            double handLengthLeft = Math.Abs(skeleton.Joints[JointType.ShoulderLeft].Position.X - skeleton.Joints[JointType.HandLeft].Position.X);
            double handLengthRight = Math.Abs(skeleton.Joints[JointType.ShoulderRight].Position.X - skeleton.Joints[JointType.HandRight].Position.X);

            double angleLenLeft = Math.Abs(skeleton.Joints[JointType.ShoulderLeft].Position.X - skeleton.Joints[JointType.ElbowLeft].Position.X);
            double angleLenRight = Math.Abs(skeleton.Joints[JointType.ShoulderRight].Position.X - skeleton.Joints[JointType.ElbowRight].Position.X);

            double rha = leveysRight / korkeusRight;
            rha = Math.Atan(rha);
            rha = rha * (180 / Math.PI);

            double lha = leveysLeft / korkeusLeft;
            lha = Math.Atan(lha);
            lha = lha * (180 / Math.PI);

            if (skeleton.Joints[JointType.WristRight].Position.Y < skeleton.Joints[JointType.ShoulderRight].Position.Y)
                ralhaalla = true;
            else
                ralhaalla = false;
            if (skeleton.Joints[JointType.WristLeft].Position.Y < skeleton.Joints[JointType.ShoulderLeft].Position.Y)
                lalhaalla = true;
            else
                lalhaalla = false;

            if (ralhaalla)
                rha = 180 - rha;
            if (lalhaalla)
                lha = 180 - lha;

            double jax;
            if (skeleton.Joints[JointType.HipCenter].Position.X < -0.7)
                jax = -0.7;
            else if (skeleton.Joints[JointType.HipCenter].Position.X > 0.7)
                jax = 0.7;
            else
                jax = skeleton.Joints[JointType.HipCenter].Position.X;
            

            //try
            //{
            //    toks.Text = "Kallelta: " + robotti.showme();
            //}
            //catch { };
            //tvks.Text = "Jalat x: " + jax;
            if (kallePaalla == true)
            {
                if (theEnding == true)
                {

                    if (null != this.sensor)
                    {
                        this.sensor.Stop();
                    }
                    robotti.kallereunaan = true;
                    
                }
                else
                {
                    keikutaKallea((int)lha, (int)rha, jax);
                }
            }

            if (differenceLeft <= 0.18 && differenceRight <= 0.18 && jjj == 1)
            {
                if (handLengthLeft >= handLenght && handLengthRight >= handLenght)
                {
                    
                    if (!laskee)
                    {
                        if(theEnding == false)
                            robotti.kallereunaan = false;

                        var seconds = 2; //countdown time
                        var start = DateTime.UtcNow; // Use UtcNow instead of Now
                        endTime = start.AddSeconds(seconds); //endTime is a member, not a local variable
                        laskee = true;
                    }

                    bool testi = false;

                    if (DateTime.UtcNow >= endTime)
                    {
                        if (theThird == 0)
                        {
                            testi = true;
                            laskee = false;
                        }
                        else
                        {
                            robotti.kallereunaan = true;
                            poistumassa = true;
                            Countdown(5, TimeSpan.FromSeconds(1), 1);
                            thirdpage.kiitos.Visibility = Visibility.Visible;                          
                        }
                    }


                    if (testi == true && theThird == 0)
                    {
                        SecondPage snapshot = new SecondPage();
                        screenshot = 1;
                        this.Content = snapshot;
                    }
                }
                else
                {
                    laskee = false;
                }
                
            }
            else
            {
                laskee = false;
            }
      
        }


        /// <summary>
        /// Draws a skeleton's bones and joints
        /// </summary>
        /// <param name="skeleton">skeleton to draw</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        //private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext)
        //{

        //    // Render Head and Shoulders
        //    this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter);
        //    this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft);
        //    this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight);

        //    // Left Arm
        //    this.DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.HandLeft);
            

        //    // Right Arm
        //    this.DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.HandRight);
        //}

        /// <summary>
        /// Maps a SkeletonPoint to lie within our render space and converts to Point
        /// </summary>
        /// <param name="skelpoint">point to map</param>
        /// <returns>mapped point</returns>
        private System.Windows.Point SkeletonPointToScreen(SkeletonPoint skelpoint)
        {
            // Convert point to depth space.  
            // We are not using depth directly, but we do want the points in our 640x480 output resolution.
            DepthImagePoint depthPoint = this.sensor.MapSkeletonPointToDepth(
                                                                             skelpoint,
                                                                             DepthImageFormat.Resolution640x480Fps30);
            return new System.Windows.Point(depthPoint.X, depthPoint.Y);
        }

        /// <summary>
        /// Draws a bone line between two joints
        /// </summary>
        /// <param name="skeleton">skeleton to draw bones from</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        /// <param name="jointType0">joint to start drawing from</param>
        /// <param name="jointType1">joint to end drawing at</param>
        //private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1)
        //{
        //    Joint joint0 = skeleton.Joints[jointType0];
        //    Joint joint1 = skeleton.Joints[jointType1];

        //    // If we can't find either of these joints, exit
        //    if (joint0.TrackingState == JointTrackingState.NotTracked ||
        //        joint1.TrackingState == JointTrackingState.NotTracked)
        //    {
        //        return;
        //    }

        //    // Don't draw if both points are inferred
        //    if (joint0.TrackingState == JointTrackingState.Inferred &&
        //        joint1.TrackingState == JointTrackingState.Inferred)
        //    {
        //        return;
        //    }

        //    // We assume all drawn bones are inferred unless BOTH joints are tracked
        //    Pen drawPen = this.inferredBonePen;
        //    if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked)
        //    {
        //        drawPen = this.trackedBonePen;
        //    }

        //}
        private void RenderClippedEdges(Skeleton skeleton)
        {
            if (shuttingdown == false && !skeleton.ClippedEdges.HasFlag(FrameEdges.Left) && !skeleton.ClippedEdges.HasFlag(FrameEdges.Right) && !skeleton.ClippedEdges.HasFlag(FrameEdges.Top))
            {
                if ((jjj != 0) && ((!beanthere) || (poistumassa)))
                {
                    //robotti.kallereunaan = false;
                    beanthere = true;
                }
                varoitus.Text = "";
            }

            if (skeleton.ClippedEdges.HasFlag(FrameEdges.Right))
            {
                if (jjj != 0)
                {
                    //robotti.kallereunaan = true;
                    beanthere = false;
                }
                varoitus.Text = "Liiku vasemmalle!";
            }

            if (skeleton.ClippedEdges.HasFlag(FrameEdges.Left))
            {
                if (jjj != 0)
                {
                    //robotti.kallereunaan = true;
                    beanthere = false;
                }
                varoitus.Text = "Liiku oikealle!";
                
            }

            if (skeleton.ClippedEdges.HasFlag(FrameEdges.Top))
            {
                if (jjj != 0)
                {
                    //robotti.kallereunaan = true;
                    beanthere = false;
                }
                varoitus.Text = "Liiku taaksepäin!";
            }

            
            
        }
       
    }
}